package com.jy.appmarket.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.webkit.URLUtil;
import android.widget.ImageView;

public class AsyncImageLoader {

	private static final String TAG = "AsyncImageLoader";

	private MemoryCache mMemoryCache;
	private FileCache mFileCache;
	private Map<ImageView, String> imageViews = Collections
			.synchronizedMap(new WeakHashMap<ImageView, String>());
	private ThreadPoolExecutor executorService;

	private boolean mIsCompress = true;

	private static AsyncImageLoader mInstance = null;

	public static AsyncImageLoader getInstance(Context c) {
		if (mInstance == null) {
			mInstance = new AsyncImageLoader(c);
		}
		return mInstance;
	}

	private AsyncImageLoader(Context context) {
		mMemoryCache = new MemoryCache();
		mFileCache = new FileCache(context);
		executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
	}

	public void displayImage(String url, ImageView imageView, int defaultId, boolean isCompress) {
		if (TextUtils.isEmpty(url)) {
			imageView.setImageResource(defaultId);
			return;
		}

		mIsCompress = isCompress;
		imageViews.put(imageView, url);
		Bitmap bitmap = mMemoryCache.get(url.hashCode());
		if (bitmap != null) {
			imageView.setImageBitmap(bitmap);
			// LogUtil.d(TAG, "set bitmap");
		} else {
			imageView.setImageResource(defaultId);
			queuePhoto(url, imageView, defaultId);
			// LogUtil.d(TAG, "defalut id...");
		}
	}

	private void queuePhoto(String url, ImageView imageView, int defaultId) {
		PhotoToLoad p = new PhotoToLoad(url, imageView, defaultId);
		executorService.submit(new ImagesLoader(p));
	}

	private Bitmap getBitmap(String url, Context c) {

		if (URLUtil.isHttpUrl(url)) { // from web
			File file = mFileCache.getFile(url);
			Bitmap b = decodeFile(file);
			if (b != null) {
				return b;
			}
			try {
				Bitmap bitmap = null;
				URL imageURL = new URL(url);
				HttpURLConnection conn = null;
				if (NetTools.isCmwap(c)) {
					conn = NetTools.getCmwapConnect(url);
				} else {
					conn = (HttpURLConnection) imageURL.openConnection();
				}
				conn.setConnectTimeout(30000);
				conn.setReadTimeout(30000);
				conn.setInstanceFollowRedirects(true);
				NetTools.setCommonHttpHeader(conn);

				int statusCode = conn.getResponseCode();
				if (statusCode != 200) {
					LogUtil.w(TAG, "http code error:" + statusCode);
					return null;
				}
				
				if(conn.getContentLength() >= 1024 * 1024){
					LogUtil.w(TAG, "image is too large");
					return null;
				}
				

				InputStream is = conn.getInputStream();
				OutputStream os = new FileOutputStream(file);
				IOTools.copyStream(is, os);
				os.close();
				bitmap = decodeFile(file);
				return bitmap;
			} catch (Exception ex) {
				file.delete();
				ex.printStackTrace();
				LogUtil.w(TAG, "url:" + url);
				return null;
			}
		} else { // local file
			File f = new File(url);
			return decodeFile(f);
		}
	}

	private Bitmap decodeFile(File file) {
		if (!file.exists()) {
			return null;
		}
		try {
			if (mIsCompress) {

				BitmapFactory.Options op = new BitmapFactory.Options();
				op.inJustDecodeBounds = true;
				BitmapFactory.decodeStream(new FileInputStream(file), null, op);

				// Find the correct scale value. It should be the power of 2.
				final int REQUIRED_SIZE = 70;
				int width_tmp = op.outWidth;
				int height_tmp = op.outHeight;
				int scale = 1;
				while (true) {
					if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
						break;
					width_tmp /= 2;
					height_tmp /= 2;
					scale *= 2;
				}

				BitmapFactory.Options op2 = new BitmapFactory.Options();
				op2.inSampleSize = scale;
				return BitmapFactory.decodeStream(new FileInputStream(file), null, op2);

			} else {
				return BitmapFactory.decodeStream(new FileInputStream(file));
			}
		} catch (Exception e) {
			e.printStackTrace();
			LogUtil.w(TAG, "decodeFile erro.." + e.toString());
		} catch (OutOfMemoryError oom) {
			oom.printStackTrace();
			LogUtil.w(TAG, "decodeFile OOM Happend.." + oom.toString());
		}
		return null;
	}

	// Task for the queue
	private class PhotoToLoad {
		public String url;
		public ImageView imageView;
		public int defaultId;

		public PhotoToLoad(String u, ImageView i, int id) {
			url = u;
			imageView = i;
			defaultId = id;
		}
	}

	class ImagesLoader implements Runnable {
		PhotoToLoad photoToLoad;

		ImagesLoader(PhotoToLoad photoToLoad) {
			this.photoToLoad = photoToLoad;
		}

		@Override
		public void run() {
			if (imageViewReused(photoToLoad))
				return;
			Bitmap bmp = getBitmap(photoToLoad.url, photoToLoad.imageView.getContext());
			mMemoryCache.put(photoToLoad.url.hashCode(), bmp);
			if (imageViewReused(photoToLoad))
				return;
			BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
			Activity a = (Activity) photoToLoad.imageView.getContext();
			a.runOnUiThread(bd);
		}
	}

	boolean imageViewReused(PhotoToLoad photoToLoad) {
		String tag = imageViews.get(photoToLoad.imageView);
        return tag == null || !tag.equals(photoToLoad.url);
    }

	// Used to display bitmap in the UI thread
	class BitmapDisplayer implements Runnable {
		Bitmap bitmap;
		PhotoToLoad photoToLoad;

		public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
			bitmap = b;
			photoToLoad = p;
		}

		public void run() {
			if (imageViewReused(photoToLoad))
				return;
			if (bitmap != null) {

				photoToLoad.imageView.setImageBitmap(bitmap);
				// photoToLoad.imageView.postInvalidate();
				// photoToLoad.imageView.startAnimation(
				// AnimationUtils.loadAnimation(photoToLoad.imageView.getContext(),
				// android.R.anim.fade_in));

			} else
				photoToLoad.imageView.setImageResource(photoToLoad.defaultId);
		}
	}

	public void clearWaitQuque() {
		while (executorService.getQueue().size() > 0) {
			Runnable r = executorService.getQueue().peek();
			executorService.remove(r);
		}
		executorService.purge();
	}

	public void clearCache() {
		mMemoryCache.clear();
		// mFileCache.clear();
	}

	/**
	 * 同步下载图片
	 * 
	 * @param url
	 * @param context
	 * @return
	 */
	public Bitmap downloadImage(String url, Context context) {
		if (url == null) {
			return null;
		}
		Bitmap bitmap = mMemoryCache.get(url.hashCode());
		if (bitmap != null) {
			return bitmap;
		} else {
			Bitmap bmp = getBitmap(url, context);
			mMemoryCache.put(url.hashCode(), bmp);
			return bmp;
		}
	}
}